package com.helloworld;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.media.Ringtone;
import android.media.RingtoneManager;
import android.media.MediaPlayer.OnCompletionListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.os.Vibrator;
import android.view.View;
import android.view.WindowManager;

import android.view.View.OnClickListener;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.*;

import	android.widget.*;
import android.widget.AdapterView.OnItemSelectedListener;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReentrantLock;



public class MainActivity extends Activity implements OnClickListener, OnCompletionListener{
    /** Called when the activity is first created. */

	//audio recorder
	private static final String[] m={"96000","88200","64000","48000","44100","32000","22050","16000","11025","8000","6000"}; 
	public static int SAMPLE_RATE = 44100;
	private static Spinner mSpinner;
	private static ArrayAdapter<String> adapter; 
	private static ProgressBar mProgressBar;
	private Button buttonRecord;
	private Button buttonPlay;
	private static File currentFile;
	private MediaPlayer mMediaPlayer;
	private static Boolean mIsRecording;
	private static AudioRecord mRecorder;
	private static File mRecording;
	private short[] mBuffer;
	
	
	private TextView _textView;
	private Button _butonClientStart;
	private Button _buttonClientStop;
	private EditText _editTextIP;


	private Socket mSocket;
	private BufferedReader mBufferedReader = null;
	private PrintWriter mPrintWriter = null;

	 private Thread mSenderThread;
	 private Thread mReaderThread;
	 private String PREFS_NAME="DUSIJUN";
	 Boolean isExit;
	 private  Ringtone ringtone;
	
	 
	 private static LinearLayout _Screen;
	
	
//	OnClickListener _onclick;
	
//?	private Button _abutton;
	
	//lock
	   private static Semaphore semaphore;
	 
	 
	 
	  private EditText _serverIp;
	

	    private static Button _buttonFS;
	    
	    
	private EditText _editTextServer;
	private EditText _editTextClientName;
	private EditText _editTextPort;
	    private String serverIpAddress = "";
	    private String clientName="";
	    private int _serverPort;
	    
	

	    private boolean connected = false;

	    private Handler handler = new Handler();
	
	
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        mSocket=null;
        isExit=false;
        mIsRecording=false;
        LinkUI();        
     
        recordingActionMapping();
        AdjustBrightness(100);      
        loadPreferences();
        semaphore=new Semaphore(1);
        _butonClientStart.requestFocus();
        //TODO if connected disable all UI
        
    }
	@Override
	public void onDestroy() {
		//if(mRecorder!=null)
	//	mRecorder.release();
		super.onDestroy();
	}   
    private void AdjustBrightness(int iPersent ){
    	/*iPersent max 100*/
    	 getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         WindowManager.LayoutParams lp = getWindow().getAttributes();  	 		
 		lp.screenBrightness = iPersent / 100.0f;
 	    getWindow().setAttributes(lp);
    }
public void LinkUI(){
	
     //  _view = (View)findViewById(R.layout);
       _butonClientStart= (Button) findViewById(R.id.button1);
       _buttonClientStop= (Button) findViewById(R.id.button3);
       _buttonFS=(Button) findViewById(R.id.buttonFS);
       _editTextIP=(EditText)findViewById(R.id.editTextIP);
     //  _editTextMessage=(EditText)findViewById(R.id.editTextMessage);
  
       _editTextClientName=(EditText)findViewById(R.id.editTextClientName);
       _editTextPort=(EditText)findViewById(R.id.editTextPort);
       
       _butonClientStart.setOnClickListener(this);
       _buttonClientStop.setOnClickListener(this);
       _buttonFS.setOnClickListener(this);
       _Screen = (LinearLayout)findViewById(R.id.mylinerlayout);
       
       //audio recorder
       
       mSpinner=(Spinner)findViewById(R.id.spinner1);
       adapter = new ArrayAdapter<String>(this,android.R.layout.simple_spinner_item,m);  
       initSpinner();
   
   	mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
	buttonRecord = (Button) findViewById(R.id.buttonRecordStart);
	buttonPlay=(Button) findViewById(R.id.buttonPlay);	
}
private void EnalbeDisalbeUI(Boolean input){
	_butonClientStart.setEnabled(input);
 
    _editTextIP.setEnabled(input);

    _editTextClientName.setEnabled(false);
    _editTextPort.setEnabled(false);
    
    mSpinner.setEnabled(input);
  
	buttonRecord.setEnabled(input);
	buttonPlay.setEnabled(input);
}
private void DisableUI(){
	   //  _view = (View)findViewById(R.layout);
    
}


private void StartRecording(){
	mIsRecording = true;
	initRecorder();
	mRecorder.startRecording();
	mRecording = getFile("raw");
	currentFile=mRecording;
	startBufferedWrite(mRecording);
	DisplayMessage("Recording...");
}
private void StopRecording(){
	try {
		semaphore.acquire();
		mIsRecording = false;
		mRecorder.stop();
		File waveFile = getFile("wav");
		currentFile=waveFile;
		try {
			rawToWave(mRecording, waveFile);
		} catch (IOException e) {
			DisplayMessage(e.getLocalizedMessage());
		}
		semaphore.release();
		DisplayMessage("Recorded to " + waveFile.getName());
	} catch (InterruptedException e1) {
	
		DisplayMessage(e1.getLocalizedMessage());
	}finally{
		
	}
	
}
private void initRecorder() {
	int bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
			AudioFormat.ENCODING_PCM_16BIT);
	mBuffer = new short[bufferSize];
	mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO,
			AudioFormat.ENCODING_PCM_16BIT, bufferSize);
}
private void recordingActionMapping(){
	
	
	
	buttonRecord.setOnClickListener(new View.OnClickListener() {
	//	@Override
		public void onClick(final View v) {
			if (!mIsRecording) {
				buttonRecord.setText("Recording..");
				StartRecording();
			}
			else {
				buttonRecord.setText("RecordStart");
				StopRecording();
			}
		}
	});


    buttonPlay.setOnClickListener(new View.OnClickListener(){
    		
    	public void onClick(final View v) {
    		
    		if (currentFile!=null){
    			DisplayMessage(buttonPlay.getText().toString());
    			if(buttonPlay.getText().toString().equals("Play")){
    		
    				if(mMediaPlayer==null){
    					
    		        mMediaPlayer= new MediaPlayer();
    				mMediaPlayer.setOnCompletionListener(MainActivity.this);
    				
    				//mMediaPlayer.setDisplay(holder); //? for video only?>
    				
    				
    				}
    		
    		try {
    			mMediaPlayer.reset();
				mMediaPlayer.setDataSource(currentFile.getPath());
			} catch (IllegalArgumentException e) {
				DisplayMessage(e.getLocalizedMessage());
			
			} catch (IllegalStateException e) {
				DisplayMessage(e.getLocalizedMessage());
			
			} catch (IOException e) {
				DisplayMessage(e.getLocalizedMessage());
			}
    		
    		try {
				mMediaPlayer.prepare();
				mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
	    		mMediaPlayer.start();
			} catch (IllegalStateException e) {
			
				DisplayMessage(e.getLocalizedMessage());
			} catch (IOException e) {
		
				DisplayMessage(e.getLocalizedMessage());
			}
    	
    	
    		buttonPlay.setText("Stop playback");
    			}else{
    			
    				if(mMediaPlayer!=null){
    					mMediaPlayer.stop();
    					buttonPlay.setText("Play");
    				}
    				
    				
    			}
    		
    		}
    	}
    		
    		
    }
    		
    		);		
}


private void initSpinner(){
	
	
    adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);  
    
     
    mSpinner.setAdapter(adapter);         
    mSpinner.setVisibility(View.VISIBLE); 
    mSpinner.setSelection(4);
    SAMPLE_RATE= 44100;
    mSpinner.setOnItemSelectedListener(new SpinnerSelectedListener());  

}
class SpinnerSelectedListener implements OnItemSelectedListener{  

	public void onItemSelected(AdapterView<?> arg0, View arg1,
			int arg2, long arg3) {
		DisplayMessage("Sampling Rate = "+adapter.getItem(arg2));
		SAMPLE_RATE=Integer.parseInt(adapter.getItem(arg2));
		
	}

	public void onNothingSelected(AdapterView<?> arg0) {
		// TODO Auto-generated method stub
		
	}  
}  
    private void loadPreferences(){
    	  // Restore preferences
        SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
        
        String loadPreferencesIP = settings.getString("IPADDRESS","192.168.1.101");
        _editTextIP.setText(loadPreferencesIP);
      
        String clientName = settings.getString("CLIENTNAME","UNNAMED_USER");
        _editTextClientName.setText(clientName);
        int serverPort=settings.getInt("PORT",8889);
        _editTextPort.setText(Integer.toString(serverPort));
    }
    
    private void savePreferences(){
 	   // We need an Editor object to make preference changes.
	      // All objects are from android.context.Context
		serverIpAddress=_editTextIP.getText().toString();
		clientName=_editTextClientName.getText().toString();
		_serverPort=Integer.parseInt(_editTextPort.getText().toString());
	      SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
	      SharedPreferences.Editor editor = settings.edit();
	      editor.putString("IPADDRESS", serverIpAddress);
	      editor.putString("CLIENTNAME",clientName );
	      editor.putInt("PORT",_serverPort );
	      // Commit the edits!
	      editor.commit();
		
    }
    

    private void DisplayMessage(String input){
    	Message m=new Message();
    	m.obj=input;
    	mDebugMessageHandler.sendMessage(m);
    }
	private void ShowMessage(String input){
		Toast.makeText(this, input, Toast.LENGTH_SHORT).show();
		}

    
    public void onClick(View v) {

    	
    	
    	
    	
    	
	    
    	if(v==_butonClientStart){
    		
    		
    		savePreferences(); 	
    		mSenderThread = new Thread(new ClientThread());
    		mSenderThread.start();  	
    		DisplayMessage("Connecting...");
    
    	}else if(v== _buttonClientStop){
    		DisplayMessage("Stop connection");	
    	}else if(v==_buttonFS){
    		
    		//File(Environment.getExternalStorageDirectory(),
    		
    		// Get instance of Vibrator from current Context
    		
    		ChangeColor();
    		DisplayMessage("LOL");
    	}
    }
    
    
    public void ChangeColor(){
    	Thread t= new Thread(new ChangColorTest());    	
		t.start();
    }
    public class ChangColorTest  implements Runnable{
    	
    
		public void run() {		    	
		    	try {
		    			for(int i=0;i<3;i++){
		    		    
						mBlinkHandler.sendEmptyMessageDelayed(1, 0);
						VibratorationRingToneHandler.sendEmptyMessageDelayed(1, 0);
						Thread.sleep(300);				
						mBlinkHandler.sendEmptyMessageDelayed(2, 0);
						Thread.sleep(300);					
					
		    			}
					
		    		} catch (InterruptedException e) {
						e.printStackTrace();
		    		}
		    	}	
		
    }
    private void Vibratoration() {
    	
    	
    	Vibrator v = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
		 
		// This example will cause the phone to vibrate "SOS" in Morse Code
		// In Morse Code, "s" = "dot-dot-dot", "o" = "dash-dash-dash"
		// There are pauses to separate dots/dashes, letters, and words
		// The following numbers represent millisecond lengths
		int dot = 200;      // Length of a Morse Code "dot" in milliseconds
		int dash = 500;     // Length of a Morse Code "dash" in milliseconds
		int short_gap = 200;    // Length of Gap Between dots/dashes
		int medium_gap = 500;   // Length of Gap Between Letters
		int long_gap = 1000;    // Length of Gap Between Words
		long[] pattern = {
		    0,  // Start immediately
		    dot, short_gap //, dot, short_gap, dot    // s
		//    ,medium_gap,
		//    dash, short_gap, dash, short_gap, dash, // o
		//    medium_gap,
		//    dot, short_gap, dot, short_gap, dot,    // s
		//    long_gap
		};
		 
		// Only perform this pattern one time (-1 means "do not repeat")
		v.vibrate(pattern, -1);
		
		
	
		
	
    }
    private void PlayRingTone(){
		Uri alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
		
	     if(alert == null){
	         // alert is null, using backup
	      
	        // I can't see this ever being null (as always have a default notification) but just incase
	             // alert backup is null, using 2nd backup
	             alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);     
	             if(alert==null){
	            	  alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
	             }
	       
	     }
	     if(alert!=null){
	     
	    	 ringtone= RingtoneManager.getRingtone(getApplicationContext(), alert);
	    	 ringtone.play();
	     }
	}
    
    
    
    
    Handler VibratorationRingToneHandler = new Handler(){
    	@Override
    	public void handleMessage(Message msg){
    		 if(msg.what==1){
    			 Vibratoration();
    			 PlayRingTone();
    		 }
    	}
    };
    
   static Handler mBlinkHandler = new Handler(){
    	@Override
    	public void handleMessage(Message msg){
    		 super.handleMessage(msg);
    		//   mScreen = (LinearLayout)findViewById(R.id.mylinerlayout);
    		 if(msg.what==1){
    		 _Screen.setBackgroundColor(Color.RED);
    	//	Vibratoration();
    	    Animation anim = null;  
            anim = new RotateAnimation(0.0f,+360.0f);  
            anim.setInterpolator(new AccelerateDecelerateInterpolator());  
            anim.setDuration(3000);  
           _buttonFS.startAnimation(anim); 
    		 }else if(msg.what==2){
    			 _Screen.setBackgroundColor(Color.BLACK);
    		 }
    	}
    };
    Handler mProgressBarHandler = new Handler(){
    	@Override
    	public void handleMessage(Message msg){
    	    super.handleMessage(msg);
            // 刷新
           try
             { 
          	 int invalue= ((Integer)msg.obj).intValue();
          	mProgressBar.setProgress(invalue);
         
           } catch (Exception e)
          {
          	
          }
    	}
    };

    Handler mDebugMessageHandler = new Handler(){
     	@Override
        public void handleMessage(Message msg)
          {
              super.handleMessage(msg);
              try
              { 
           	 String textContent=msg.obj.toString();
           	ShowMessage(textContent);
           	// TODO 
           	if(textContent.equals("Done!")){
           		EnalbeDisalbeUI(false);
           	}
           
            } catch (Exception e)
           {
               
           }
              
              
          }
    };
    Handler mTCPMessageHandler = new Handler()
      {
    	@Override
       public void handleMessage(Message msg)
         {
             super.handleMessage(msg);
              // 刷新
             try
               { 
            	 String textContent=msg.obj.toString();
            	 
            	 if(textContent.equals("FILE\n")){
            		 
            		 
            	 }else if (textContent.equals("START\n")){
            		 StartRecording();
            	 }else if (textContent.equals("STOP\n")){
            		 StopRecording();
            	 }else if (textContent.equals("BLINKRED\n")){            		
            		 ChangeColor();
            	 }else if (textContent.equals("BLINKBLACK\n")){
            		
            	 
            	 }else{
            	 
                 _editTextServer.append(msg.obj.toString());// 将聊天记录添加进来
            	 }
             } catch (Exception e)
            {
            	 DisplayMessage(e.getLocalizedMessage());
            }
           }
     };

     
     
     
     
    public class ClientThread implements Runnable {

        public void run() {
        	
        	
            try {
         
               mSocket = new Socket(serverIpAddress, _serverPort);
               mBufferedReader = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
               mPrintWriter = new PrintWriter(mSocket.getOutputStream(), true);
                mPrintWriter.print("Login,"+clientName+"\n");
                mPrintWriter.flush();
                mReaderThread= new Thread(new ClientReader());
        		mReaderThread.start();
        		DisplayMessage("Done!");
            } catch (Exception e) {
            	DisplayMessage(e.getLocalizedMessage());
            
            }
        }
       
    
    
    }
   
    
    
    
    public class ClientReader implements Runnable {
    	
        public void run() {
        	while(!isExit){
        		while(mBufferedReader==null){
        			try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
        		}
        		 try
        		            {
        			 String msgServer=null;
        		                 if ((msgServer = mBufferedReader.readLine()) != null)
        		                {                        
        		                	 msgServer += "\n";
        		                	 
        		                	 if(msgServer.equals("FILE\n")){
        		                		 //handel file transfer
        		                		 semaphore.acquire();
        		                		 File mfile=getFile("wav");
        		                		
        		                			byte[] rawData = new byte[(int) mfile.length()];
        		                			DataInputStream input = null;
        		                			try {
        		                				input = new DataInputStream(new FileInputStream(mfile));
        		                				input.read(rawData);
        		                			} finally {
        		                				if (input != null) {
        		                					input.close();
        		                				}
        		                			}
        		                		 
        		                			long filelength=mfile.length();
        		                			byte[] fileLengthbytes =  ByteBuffer.allocate(8).putLong(filelength).array();
        		                			mSocket.getOutputStream().write(fileLengthbytes);   
        		                			mSocket.getOutputStream().flush();
        		                			mSocket.getOutputStream().write(rawData);
        		                			mSocket.getOutputStream().flush();
        		                			semaphore.release();
        		                		
        		                		 
        		                	 }else{
        		                		 //normal message
        		                	 Message msg= new Message();
        		                	 msg.obj=msgServer;
        		                	
        		                    mTCPMessageHandler.sendMessage(msg);
        		                	 }
        		             }                    
        		             } catch (Exception e){
        		              DisplayMessage(e.getLocalizedMessage());
        		           }
         
        	}
        }
      
    }
	public void onCompletion(MediaPlayer mp) {
		// TODO Auto-generated method stub
		if(buttonPlay!=null)
		{
			buttonPlay.setText("Play");
		    DisplayMessage("PlayBack completed!");
		}
	}
	private File getFile(final String suffix) {
	//	Time time = new Time();
	//	time.setToNow(); time.format("%Y%m%d%H%M%S") + "." 
		
		return new File(Environment.getExternalStorageDirectory(),"temp."+ suffix);
	}
	private void startBufferedWrite(final File file) {
		new Thread(new Runnable() {
		//	@Override
			public void run() {
				DataOutputStream output = null;
				try {
					output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
					while (mIsRecording) {
						double sum = 0;
						int readSize = mRecorder.read(mBuffer, 0, mBuffer.length);
						for (int i = 0; i < readSize; i++) {
							output.writeShort(mBuffer[i]);
							sum += mBuffer[i] * mBuffer[i];
						}
						if (readSize > 0) {
							final double amplitude = sum / readSize;
							Message msg= new Message();
							msg.obj=(int) Math.sqrt(amplitude);
							mProgressBarHandler.sendMessage(msg);
						}
					}
				} catch (IOException e) {
					DisplayMessage(e.getLocalizedMessage());
					
				} finally {
				
					Message msg= new Message();
					msg.obj=0;
					mProgressBarHandler.sendMessage(msg);
					if (output != null) {
						try {
							output.flush();
						} catch (IOException e) {
							DisplayMessage(e.getLocalizedMessage());
						} finally {
							try {
								output.close();
							} catch (IOException e) {
								DisplayMessage(e.getLocalizedMessage());
							}
						}
					}
				}
			}
		}).start();
	}

	private void rawToWave(final File rawFile, final File waveFile) throws IOException {

		byte[] rawData = new byte[(int) rawFile.length()];
		DataInputStream input = null;
		try {
			input = new DataInputStream(new FileInputStream(rawFile));
			input.read(rawData);
		} finally {
			if (input != null) {
				input.close();
			}
		}

		DataOutputStream output = null;
		try {
			output = new DataOutputStream(new FileOutputStream(waveFile));
			// WAVE header
			// see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
			writeString(output, "RIFF"); // chunk id
			writeInt(output, 36 + rawData.length); // chunk size
			writeString(output, "WAVE"); // format
			writeString(output, "fmt "); // subchunk 1 id
			writeInt(output, 16); // subchunk 1 size
			writeShort(output, (short) 1); // audio format (1 = PCM)
			writeShort(output, (short) 1); // number of channels
			writeInt(output, SAMPLE_RATE); // sample rate
			writeInt(output, SAMPLE_RATE * 2); // byte rate
			writeShort(output, (short) 2); // block align
			writeShort(output, (short) 16); // bits per sample
			writeString(output, "data"); // subchunk 2 id
			writeInt(output, rawData.length); // subchunk 2 size
			// Audio data (conversion big endian -> little endian)
			short[] shorts = new short[rawData.length / 2];
			ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
			ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
			for (short s : shorts) {
				bytes.putShort(s);
			}
			output.write(bytes.array());
		} finally {
			if (output != null) {
				output.close();
			}
		}
	}
	private void writeInt(final DataOutputStream output, final int value) throws IOException {
		output.write(value >> 0);
		output.write(value >> 8);
		output.write(value >> 16);
		output.write(value >> 24);
	}

	private void writeShort(final DataOutputStream output, final short value) throws IOException {
		output.write(value >> 0);
		output.write(value >> 8);
	}

	private void writeString(final DataOutputStream output, final String value) throws IOException {
		for (int i = 0; i < value.length(); i++) {
			output.write(value.charAt(i));
		}
	}	
}